package ${domain}.module.wsys.mgr;

import ${domain}.frame.auth.LocalData;
import ${domain}.frame.auth.Token;
import ${domain}.frame.base.ErrorType;
import ${domain}.frame.schedule.RunCronTask;
import ${domain}.frame.schedule.RunDelayRepeatTask;
import ${domain}.frame.schedule.RunFixRepeatTask;
import ${domain}.frame.schedule.Scheduler;
import ${domain}.frame.utils.IDgenerator;
import ${domain}.frame.utils.MapperUtil;
import ${domain}.frame.utils.Message;
import ${domain}.frame.utils.SqlUtil;
import ${domain}.frame.utils.ValidationUtil;
import ${domain}.module.wsys.ent.TaskSql;
import ${domain}.module.wsys.mpr.TaskSqlMapper;
import ${domain}.module.wsys.req.TaskSqlCreateRequest;
import ${domain}.module.wsys.req.TaskSqlDeleteRequest;
import ${domain}.module.wsys.req.TaskSqlFindRequest;
import ${domain}.module.wsys.req.TaskSqlUpdateRequest;
import ${domain}.module.wsys.rsp.TaskSqlCreateResponse;
import ${domain}.module.wsys.rsp.TaskSqlDeleteResponse;
import ${domain}.module.wsys.rsp.TaskSqlFindResponse;
import ${domain}.module.wsys.rsp.TaskSqlUpdateResponse;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.support.CronSequenceGenerator;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;

/**
 * TASK_SQL - SQL任务
 *
 * @author author
 * @version 0.0.1
 * @since 2020-05-24
 */
@Transactional
@Service
public class TaskSqlManagerImpl implements TaskSqlManager {

    @Autowired
    private TaskSqlMapper taskSqlMapper;
    @Autowired
    private Scheduler scheduler;

    /**
     * 插入
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    public TaskSqlCreateResponse create(TaskSqlCreateRequest request, Token token) {
        TaskSqlCreateResponse response = new TaskSqlCreateResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        if ("Cron".equals(request.getTaskType())) {
            try {
                new CronSequenceGenerator(request.getTypeValue());
            } catch (Exception e) {
                response.addError(ErrorType.BUSINESS_ERROR, "Cron表达式错误!");
                return response;
            }
        } else {
            String typeValue = request.getTypeValue();
            try {
                Integer.parseInt(typeValue);
            } catch (Exception e) {
                response.addError(ErrorType.BUSINESS_ERROR, "类型属值错误!");
                return response;
            }
        }

        long id = IDgenerator.nextId();
        TaskSql entity = MapperUtil.map(request, TaskSql.class);
        entity.setId(id);

        long result = taskSqlMapper.insert(entity, token);
        if (1L != result) {
            response.addError(ErrorType.BUSINESS_ERROR, Message.CREATE_FAILURE);
            return response;
        }
        response.setId(id);
        createOrRepeat(entity);

        return response;
    }

    /**
     * 逻辑删除
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    public TaskSqlDeleteResponse delete(TaskSqlDeleteRequest request, Token token) {
        TaskSqlDeleteResponse response = new TaskSqlDeleteResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        long result = taskSqlMapper.delete(request.getId(), token);
        if (1L != result) {
            response.addError(ErrorType.BUSINESS_ERROR, Message.DELETE_FAILURE);
            return response;
        }
        response.setResult(result);
        scheduler.remove(String.valueOf(request.getId()));

        return response;
    }

    /**
     * 更新
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    public TaskSqlUpdateResponse update(TaskSqlUpdateRequest request, Token token) {
        TaskSqlUpdateResponse response = new TaskSqlUpdateResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        if ("Cron".equals(request.getTaskType())) {
            try {
                new CronSequenceGenerator(request.getTypeValue());
            } catch (Exception e) {
                response.addError(ErrorType.BUSINESS_ERROR, "Cron表达式错误!");
                return response;
            }
        } else {
            String typeValue = request.getTypeValue();
            try {
                Integer.parseInt(typeValue);
            } catch (Exception e) {
                response.addError(ErrorType.BUSINESS_ERROR, "类型属值错误!");
                return response;
            }
        }

        TaskSql entity = taskSqlMapper.getById(request.getId(), token);
        if (entity == null) {
            response.addError(ErrorType.BUSINESS_ERROR, Message.GET_FAILURE);
            return response;
        }

        MapperUtil.map(request, entity);
        long result = taskSqlMapper.update(entity, token);
        if (1L != result) {
            response.addError(ErrorType.BUSINESS_ERROR, Message.UPDATE_FAILURE);
            return response;
        }
        response.setResult(result);
        if (request.getValid()) {
            createOrRepeat(MapperUtil.map(request, TaskSql.class));
        } else {
            scheduler.remove(String.valueOf(request.getId()));
        }

        return response;
    }

    /**
     * 查询
     *
     * @param request 请求对象
     * @param token   令牌
     * @return 响应
     */
    @Transactional(readOnly = true)
    public TaskSqlFindResponse find(TaskSqlFindRequest request, Token token) {
        TaskSqlFindResponse response = new TaskSqlFindResponse();

        ValidationUtil.validate(request, response);
        if (response.hasError()) {
            return response;
        }

        if (request.getPageSize() != 0) {
            PageHelper.startPage(request.getPageNumber(), request.getPageSize());
        }
        if (StringUtil.isNotEmpty(request.getSortKey())) {
            PageHelper.orderBy(request.getSortKey() + " " + request.getSortType());
        }
        PageInfo<TaskSql> pageInfo = new PageInfo<>(taskSqlMapper.find(request, token));

        response.setResult(pageInfo.getList());
        response.setTotalCount(pageInfo.getTotal());

        return response;
    }

    /**
     * 添加或替换Sql任务对象
     *
     * @param taskSql Sql任务对象
     * @return
     */
    public boolean createOrRepeat(TaskSql taskSql) {
        try {
            if ("Cron".equals(taskSql.getTaskType())) {
                scheduler.createOrRepeat(new RunCronTask() {

                    @Override
                    public String cron() {
                        return taskSql.getTypeValue();
                    }

                    @Override
                    public String taskName() {
                        return taskSql.getTaskName();
                    }

                    @Override
                    public String taskId() {
                        return String.valueOf(taskSql.getId());
                    }

                    @Override
                    public String taskNote() {
                        return taskSql.getTaskNote();
                    }

                    @Override
                    protected void task() {
                        try {
                            SqlUtil.exec(taskSql.getTaskSql());
                        } catch (Exception e) {
                            throw new RuntimeException(String.format("[%s]执行异常！任务ID(%s)", taskName(), taskId()));
                        }
                    }
                });
            }
            if ("DelayRepeat".equals(taskSql.getTaskType())) {
                scheduler.createOrRepeat(new RunDelayRepeatTask() {
                    @Override
                    public Duration interval() {
                        String typeValue = taskSql.getTypeValue();
                        return Duration.ofSeconds(Integer.parseInt(typeValue));
                    }

                    @Override
                    public String taskName() {
                        return taskSql.getTaskName();
                    }

                    @Override
                    public String taskId() {
                        return String.valueOf(taskSql.getId());
                    }

                    @Override
                    public String taskNote() {
                        return taskSql.getTaskNote();
                    }

                    @Override
                    protected void task() {
                        try {
                            SqlUtil.exec(taskSql.getTaskSql());
                        } catch (Exception e) {
                            throw new RuntimeException(String.format("[%s]执行异常！任务ID(%s)", taskName(), taskId()));
                        }
                    }
                });
            }
            if ("FixRepeat".equals(taskSql.getTaskType())) {
                scheduler.createOrRepeat(new RunFixRepeatTask() {
                    @Override
                    public Duration interval() {
                        String typeValue = taskSql.getTypeValue();
                        return Duration.ofSeconds(Integer.parseInt(typeValue));
                    }

                    @Override
                    public String taskName() {
                        return taskSql.getTaskName();
                    }

                    @Override
                    public String taskId() {
                        return String.valueOf(taskSql.getId());
                    }

                    @Override
                    public String taskNote() {
                        return taskSql.getTaskNote();
                    }

                    @Override
                    protected void task() {
                        try {
                            SqlUtil.exec(taskSql.getTaskSql());
                        } catch (Exception e) {
                            throw new RuntimeException(String.format("[%s]执行异常！任务ID(%s)", taskName(), taskId()));
                        }
                    }
                });
            }
        } catch (Exception e) {
            return false;
        }
        return true;
    }
}
